// 本地文件管理服务
import fs from 'fs'
import path from 'path'
import { createHash } from 'crypto'
import { HttpsProxyAgent } from 'https-proxy-agent'
import fetch from 'node-fetch'

interface DownloadResult {
  success: boolean
  filePath?: string
  error?: string
  fileSize?: number
}

class FileManager {
  private tempDir: string

  constructor() {
    // 创建下载文件目录（永久保存）
    this.tempDir = path.join(process.cwd(), 'downloads', 'audio')
    this.ensureDirectoryExists(this.tempDir)
    console.log('文件管理器初始化成功，下载目录:', this.tempDir)
  }

  /**
   * 确保目录存在
   * @param dirPath 目录路径
   */
  private ensureDirectoryExists(dirPath: string): void {
    if (!fs.existsSync(dirPath)) {
      fs.mkdirSync(dirPath, { recursive: true })
      console.log('创建目录:', dirPath)
    }
  }

  /**
   * 生成本地文件路径
   * @param originalUrl 原始URL
   * @param extension 文件扩展名
   * @returns 本地文件路径
   */
  private generateLocalFilePath(originalUrl: string, extension: string = '.mp3'): string {
    // 使用URL的MD5作为文件名，确保唯一性
    const hash = createHash('md5').update(originalUrl).digest('hex')
    const timestamp = Date.now()
    const fileName = `${timestamp}-${hash}${extension}`
    
    return path.join(this.tempDir, fileName)
  }

  /**
   * 创建带代理的fetch配置
   * @returns 配置了代理的fetch选项
   */
  private createProxyFetchOptions(): RequestInit {
    const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY

    if (!proxyUrl) {
      return {}
    }

    console.log('配置代理:', proxyUrl)

    // 创建代理agent
    const agent = new HttpsProxyAgent(proxyUrl)

    return {
      agent: agent as any // node-fetch支持agent选项
    }
  }

  /**
   * 带重试机制的fetch请求
   * @param url 请求URL
   * @param options 请求选项
   * @param maxRetries 最大重试次数
   * @returns Response对象
   */
  private async fetchWithRetry(url: string, options: RequestInit, maxRetries: number = 3): Promise<Response> {
    let lastError: Error | null = null
    const proxyOptions = this.createProxyFetchOptions()

    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        console.log(`尝试下载 (${attempt}/${maxRetries}):`, url)

        const response = await fetch(url, {
          ...options,
          ...proxyOptions,
          timeout: 30000 // 30秒超时
        })

        if (response.ok) {
          console.log(`下载成功 (尝试 ${attempt}):`, response.status, response.statusText)
          return response as Response
        } else {
          throw new Error(`HTTP ${response.status} ${response.statusText}`)
        }

      } catch (error) {
        lastError = error instanceof Error ? error : new Error('Unknown error')
        console.warn(`下载失败 (尝试 ${attempt}/${maxRetries}):`, lastError.message)

        if (attempt < maxRetries) {
          // 指数退避：1秒、2秒、4秒
          const delay = Math.pow(2, attempt - 1) * 1000
          console.log(`等待 ${delay}ms 后重试...`)
          await new Promise(resolve => setTimeout(resolve, delay))
        }
      }
    }

    throw lastError || new Error('下载失败')
  }

  /**
   * 从URL下载文件到本地
   * @param fileUrl 文件URL
   * @returns 下载结果
   */
  async downloadFromUrl(fileUrl: string): Promise<DownloadResult> {
    try {
      console.log('开始下载音频文件:', fileUrl)

      // 准备请求选项
      const fetchOptions: RequestInit = {
        headers: {
          'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
          'Accept': 'audio/*,*/*;q=0.9',
          'Accept-Language': 'en-US,en;q=0.5',
          'Accept-Encoding': 'gzip, deflate, br',
          'Connection': 'keep-alive',
          'Upgrade-Insecure-Requests': '1',
          'Referer': 'https://www.tiktok.com/',
          'Sec-Fetch-Dest': 'audio',
          'Sec-Fetch-Mode': 'no-cors',
          'Sec-Fetch-Site': 'cross-site'
        }
      }

      // 发起下载请求（带重试机制和代理）
      const response = await this.fetchWithRetry(fileUrl, fetchOptions, 3)

      if (!response.ok) {
        throw new Error(`下载失败: HTTP ${response.status} ${response.statusText}`)
      }

      // 获取文件扩展名
      const contentType = response.headers.get('content-type') || ''
      const extension = this.getExtensionFromContentType(contentType) || this.getExtensionFromUrl(fileUrl)
      
      // 生成本地文件路径
      const localFilePath = this.generateLocalFilePath(fileUrl, extension)
      
      // 下载文件内容
      const arrayBuffer = await response.arrayBuffer()
      const buffer = Buffer.from(arrayBuffer)
      
      // 写入本地文件
      fs.writeFileSync(localFilePath, buffer)
      
      console.log(`文件下载成功: ${fileUrl} -> ${localFilePath}`)
      console.log(`文件大小: ${buffer.length} bytes`)

      return {
        success: true,
        filePath: localFilePath,
        fileSize: buffer.length
      }

    } catch (error) {
      console.error('下载文件失败:', error)
      return {
        success: false,
        error: error instanceof Error ? error.message : 'Unknown error'
      }
    }
  }

  /**
   * 批量下载文件
   * @param fileUrls 文件URL列表
   * @returns 下载结果列表
   */
  async batchDownloadFromUrls(fileUrls: string[]): Promise<DownloadResult[]> {
    const results: DownloadResult[] = []
    
    for (const fileUrl of fileUrls) {
      const result = await this.downloadFromUrl(fileUrl)
      results.push(result)
      
      // 添加小延迟避免请求过于频繁
      await new Promise(resolve => setTimeout(resolve, 100))
    }
    
    return results
  }

  /**
   * 删除本地文件
   * @param filePath 文件路径
   * @returns 删除结果
   */
  deleteFile(filePath: string): boolean {
    try {
      if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath)
        console.log('本地文件删除成功:', filePath)
        return true
      }
      return true // 文件不存在也算成功
    } catch (error) {
      console.error('删除本地文件失败:', error)
      return false
    }
  }

  /**
   * 批量删除文件
   * @param filePaths 文件路径列表
   * @returns 删除结果
   */
  batchDeleteFiles(filePaths: string[]): boolean {
    let allSuccess = true
    
    for (const filePath of filePaths) {
      if (!this.deleteFile(filePath)) {
        allSuccess = false
      }
    }
    
    return allSuccess
  }

  /**
   * 检查文件是否存在
   * @param filePath 文件路径
   * @returns 是否存在
   */
  fileExists(filePath: string): boolean {
    return fs.existsSync(filePath)
  }

  /**
   * 获取文件大小
   * @param filePath 文件路径
   * @returns 文件大小（字节）
   */
  getFileSize(filePath: string): number {
    try {
      const stats = fs.statSync(filePath)
      return stats.size
    } catch (error) {
      return 0
    }
  }

  /**
   * 根据Content-Type获取文件扩展名
   * @param contentType Content-Type
   * @returns 文件扩展名
   */
  private getExtensionFromContentType(contentType: string): string {
    const mimeTypes: { [key: string]: string } = {
      'audio/mpeg': '.mp3',
      'audio/mp3': '.mp3',
      'audio/wav': '.wav',
      'audio/wave': '.wav',
      'audio/x-wav': '.wav',
      'audio/mp4': '.m4a',
      'audio/aac': '.aac',
      'audio/ogg': '.ogg',
      'audio/flac': '.flac',
      'audio/x-ms-wma': '.wma',
      'audio/amr': '.amr',
      'audio/opus': '.opus'
    }
    
    return mimeTypes[contentType.toLowerCase()] || '.mp3'
  }

  /**
   * 从URL中提取文件扩展名
   * @param url 文件URL
   * @returns 文件扩展名
   */
  private getExtensionFromUrl(url: string): string {
    try {
      const urlPath = new URL(url).pathname
      const ext = path.extname(urlPath).toLowerCase()
      
      // 验证是否为音频文件扩展名
      const audioExtensions = ['.mp3', '.wav', '.m4a', '.aac', '.ogg', '.flac', '.wma', '.amr', '.opus']
      return audioExtensions.includes(ext) ? ext : '.mp3'
    } catch (error) {
      return '.mp3'
    }
  }

  /**
   * 清理过期的临时文件
   * @param maxAge 最大年龄（毫秒），默认1小时
   * @returns 清理的文件数量
   */
  cleanupExpiredFiles(maxAge: number = 60 * 60 * 1000): number {
    try {
      const cutoffTime = Date.now() - maxAge
      let deletedCount = 0
      
      if (!fs.existsSync(this.tempDir)) {
        return 0
      }
      
      const files = fs.readdirSync(this.tempDir)
      
      for (const file of files) {
        const filePath = path.join(this.tempDir, file)
        
        try {
          const stats = fs.statSync(filePath)
          
          // 检查文件修改时间
          if (stats.mtime.getTime() < cutoffTime) {
            fs.unlinkSync(filePath)
            deletedCount++
            console.log('清理过期文件:', filePath)
          }
        } catch (error) {
          console.error('清理文件时出错:', filePath, error)
        }
      }
      
      console.log(`清理了 ${deletedCount} 个过期的本地文件`)
      return deletedCount
      
    } catch (error) {
      console.error('清理过期文件失败:', error)
      return 0
    }
  }

  /**
   * 获取临时目录路径
   * @returns 临时目录路径
   */
  getTempDir(): string {
    return this.tempDir
  }

  /**
   * 获取目录中的文件列表
   * @returns 文件列表
   */
  listFiles(): string[] {
    try {
      if (!fs.existsSync(this.tempDir)) {
        return []
      }
      
      return fs.readdirSync(this.tempDir).map(file => path.join(this.tempDir, file))
    } catch (error) {
      console.error('获取文件列表失败:', error)
      return []
    }
  }

  /**
   * 获取目录使用情况统计
   * @returns 统计信息
   */
  getDirectoryStats(): { fileCount: number; totalSize: number } {
    try {
      const files = this.listFiles()
      let totalSize = 0
      
      for (const filePath of files) {
        totalSize += this.getFileSize(filePath)
      }
      
      return {
        fileCount: files.length,
        totalSize
      }
    } catch (error) {
      console.error('获取目录统计失败:', error)
      return { fileCount: 0, totalSize: 0 }
    }
  }
}

export default FileManager
export type { DownloadResult }
